package com.xiyuan.smartutils.control;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 消息队列,对LinkedList进行封装，增加对象锁对队列进行控制：<br>
 * <br>
 * 1)当列表中没有数据时阻塞到队列中读取消息的线程 2)当列表中新增数据时通知所有正在阻塞的线程
 *
 * @version v1.0.0 @author lgz 2017-8-27 新建与整理
 */
public class Queue<E> implements Serializable {
    private static final long serialVersionUID = 1L;
    private final LinkedList<E> queue = new LinkedList<E>();
    
    public final ReentrantLock lock = new ReentrantLock();
    private Condition notEmpty = lock.newCondition();
    
    /**
     * 投递对象，默认从后端排队
     */
    public void post(E e) {
        post(e, false);
    }
    
    /**
     * 投递对象，优先的投放到前端，非优先投放后端
     */
    public boolean post(E e, boolean priority) {
        if (e == null) {return false;}
        
        lock.lock();
        try {
//            while (queue.size() == capacity) {
//                // 队列满了，等待队列不满
//                notFull.await();
//            }
            queue.add(e);
            notEmpty.signalAll();// // 入队后，通知可能在等待的消费者
        }
        finally {
            lock.unlock();
        }
        return true;
    }
    
    /**
     * 接收消息队列中的对象，如果当前没有则阻塞线程等待指定时间， 如果等待时间内有通知则读取，等待结束再尝试一次，未读到返回NULL
     *
     * @param timeout 等待时间，以毫秒为单位
     * @return 如果有消息，则返回消息，如果没有则返回null
     */
    public E accept(long timeout) {
        lock.lock();
        try {
            while (queue.isEmpty()) {
                // 队列空了，等待队列非空
                notEmpty.await(timeout, TimeUnit.MICROSECONDS);
                if (queue.isEmpty()) {
                    // 超时且队列仍然为空，返回null或抛出异常，这里选择返回null
                    return null;
                }
            }
            
            return queue.removeFirst();
        }
        catch (InterruptedException e) {
            return null;
        }
        finally {
            lock.unlock();
        }
    }
    
    /**
     * 对象是否存在对列中
     */
    public boolean contains(E e) {
        lock.lock();
        try {
            return queue.contains(e);
        }
        finally {
            lock.unlock();
        }
    }
    
    /**
     * 当前对列是否为空
     */
    public boolean isEmpty() {
        return queue.isEmpty();
    }
    
    /**
     * 清除队列消息
     */
    public void clear() {
        lock.lock();
        try {
            queue.clear();
        }
        finally {
            lock.unlock();
        }
    }
    
    /**
     * 获取当前队列长度
     */
    public int size() {
        return queue.size();
    }
    
    public List<E> listAll() {
        lock.lock();
        try {
            return new ArrayList<E>(queue);
        }
        finally {
            lock.unlock();
        }
    }
    
    /**
     * 移除元素
     *
     * @return true|false
     */
    public boolean remove(E e) {
        lock.lock();
        try {
            return queue.remove(e);
        }
        finally {
            lock.unlock();
        }
    }
}
